var fs = require('fs');
var util = require('util');
var path = require('path');
var myUtil = require('../../js/util.js');


exports.query = function(query, resp, callback) {
    if (isNaN(query.sid) || !query.hasOwnProperty('openid') || 
        !query.hasOwnProperty('minTime') || !query.hasOwnProperty('maxTime')) {
        resp.code = 1; resp.desc = 'invalid params'; 
        callback(); return;
    }

    var sid = +query.sid;
    var openid = query.openid;

    var db = gServers.getGameDB(sid);
    if (!db) {
        resp.code = 1; resp.desc = 'invalid server'; 
        callback(); return;
    }
    var condition = {'ts':{'$gte': query.minTime, '$lt':query.maxTime}, 'openid':openid};
    var cursor = db.collection('pay').find(condition).limit(500);
    cursor.each(function(err, item){
        if (cursor.isClosed()) {
            callback(); return;
        }
        resp.data.push([item.ts, item.billno, +item.amt*config.platform.exchange_rate, item.cash, item.state]);
    });
}

exports.topUser = function(query, resp, callback) {
    if (isNaN(query.sid)) {
        resp.code = 1; resp.desc = 'invalid params'; 
        callback(); return;
    }

    var sid = +query.sid;
    var db = gServers.getGameDB(sid);
    if (!db) {
        resp.code = 1; resp.desc = 'invalid server'; 
        callback(); return;
    }

    var dbPay = db.collection('pay');
    var dbPlat = db.collection('plat');
    var dbUser = db.collection('user');
    var ranks = [];
    var infos = {};
    var idMaps = {};
    var openids = [];
    var uids = [];

    async.series([
        function(cb) {

            if (sid >= 100) {
                dbPay.mapReduce(function(){
                    emit(this.openid, {sum:+this.amt});
                }, function(key, values){
                    var result = {sum:0};
                    values.forEach(function(value){
                        result.sum += value.sum;
                    });
                    return result;
                }, {
                    out:{ inline: 1 }
                }, function(err, res){
                    if (err) LOG(err);
                    else {
                        res.forEach(function(value){
                            ranks.push({
                                openid: value._id,
                                sum: value.value.sum
                            });
                        });

                        ranks = ranks.sort(function(a,b){return b.sum - a.sum;}).slice(0, 100);
                        ranks.forEach(function(value){
                            value.sum = parseInt(value.sum * config.platform.exchange_rate);
                            openids.push(value.openid);
                        });
                    }
                    cb();
                });
            } else {
                dbPay.group({'openid':1}, {}, {sum:0}, "function(obj,prev){prev.sum += +obj.amt;}", function(err, results) {
                    if (err || !results) {
                        cb(util.format('server %d dbPay error', sid)); return;
                    }

                    ranks = results.sort(function(a,b){return b.sum - a.sum;}).slice(0, 100);
                    ranks.forEach(function(value){
                        value.sum = parseInt(value.sum * config.platform.exchange_rate);
                        openids.push(value.openid);
                    });
                    cb();
                });
            }


        },

        function(cb) {
            var cursor = dbPlat.find({_id:{"$in":openids}}, {});
            cursor.each(function(err, item){
                if (cursor.isClosed()) {
                    cb(); return;
                }
                
                idMaps[item._id] = item.uid;
                uids.push(item.uid);
            });
        },

        function(cb) {
            var cursor = dbUser.find({_id:{"$in":uids}},{'info':1});
            cursor.each(function(err, item){
                if (cursor.isClosed()) {
                    cb(); return;
                }
                
                infos[item._id] = item;
            });
        }
    ], function(err, results) {
        if (err) {
            resp.code = 1; resp.desc = err;
        } else {
            for (var i=0; i<ranks.length; i++) {
                var user = ranks[i];
                user.uid = idMaps[user.openid];
                var info = infos[user.uid];
                if (info) {
                    user.name = info.info.un;
                    user.roll = info.info.roll;
                } else {
                    user.name = 'unknown';
                    user.roll = 0;
                }
                resp.data.push([user.openid, user.sum, user.uid, user.name, user.roll]);
            }
        }
        callback();
    });
}

exports.tops = function(query, resp, callback) {
    var limit = +query.limit || 200;
    var condition = {};

    if (query.minTime) {
        condition.ts = {'$gte': query.minTime};
    }
    if (query.maxTime) {
        if (!condition.ts) {
            condition.ts = {};
        }
        condition.ts['$lt'] = query.maxTime;
    }

    LOG("pay.tops");
    LOG("minTime: " + query.minTime);
    LOG("maxTime: " + query.maxTime);
    
    var counts = {};
    var ranks = [];
    async.each(gServers.getSids(), function(sid, cb) {
        var db = gServers.getGameDB(sid);
        if (!db) {
            cb(); return;
        }

        var dbPay = db.collection("pay");

        if (sid == 131) { // group 当key大于20000的时候出报错，不能使用，这时候使用mapReduce来统计数据
            dbPay.mapReduce(function(){
                emit(this.openid, {sum:+this.amt});
            }, function(key, values){
                var result = {sum:0};
                values.forEach(function(value){
                    result.sum += value.sum;
                });
                return result;
            }, {
                out:{ inline: 1 },
                query:condition
            }, function(err, res){
                if (err) LOG(err);
                else {
                    res.forEach(function(value){
                        addAttrValue(counts, value._id, value.value.sum);
                    });
                }
                cb();
            });
        } else {
            dbPay.group(
                {'openid':1},
                condition,
                {sum:0},
                "function(obj,prev){prev.sum += +obj.amt;}",
                function(err, results) {
                    if (err || !results) {
                        cb(util.format('server %d dbPay error', sid)); return;
                    }


                    results.forEach(function(value){
                        addAttrValue(counts, value.openid, value.sum);
                    });
                    cb();
                }
            );
        }

    }, function(err) {
        if (err) {
            resp.code = 1; resp.desc = err;
            callback(); return;
        }

        for (var openid in counts) {
            ranks.push({openid:openid, sum:counts[openid]});
        }
        ranks.sort(function(a, b) {
            return b.sum - a.sum;
        });
        for (var i = 0, max = Math.min(ranks.length, limit); i < max; ++i) {
            var rankData = ranks[i];
            resp.data.push([rankData.openid, Math.floor(rankData.sum * config.platform.exchange_rate)]);
        }
        callback();
    });
}

exports.recent = function(query, resp, callback) {
    var detailDays = 30;
    var now = new Date();
    var curZeroTime = now.zeroTime().getStamp();
    var curZeroMonth = now.zeroMonth().getStamp();
    var detailBeginTime = curZeroTime - 86400*detailDays;
    var minTime = Math.min(curZeroMonth, detailBeginTime);
    
    gStat.pay.update(curZeroTime, function(err) {
        if (err) {
            resp.code = 1; resp.desc = err;
        }
        
        var serverDatas = gStat.pay.servers;
        for (var sid in serverDatas) {
            var monthCount = 0;
            var serverDays = serverDatas[sid];
            var resultItem = [sid, 0];
            for (var time = curZeroTime; time >= minTime; time -= 86400) {
                var pay = serverDays[time] || 0;
                if (time >= curZeroMonth) {
                   monthCount += pay;
                }

                if (time >= detailBeginTime) {
                    resultItem.push(pay); 
                }
            }
            resultItem[1] = monthCount;
            resp.data.push(resultItem);
        }
        callback();
    });
}

exports.month = function(query, resp, callback) {
    var detailMonthCount = 30;
    var now = new Date();
    var curMonth = now.getFullMonth();
    
    var serverDatas = gStat.pay.servers;
    for (var sid in serverDatas) {
        var monthCount = 0;
        var serverDays = serverDatas[sid];
        var resultItem = [sid, 0];
        for (var i = 0; i <= detailMonthCount; ++i) {
            resultItem.push(0);
        }

        for (var time in serverDays) {
            var pay = serverDays[time];
            var month = curMonth - Date.createFromStamp(+time).getFullMonth();
            if (month >= 0 && month < detailMonthCount) {
                resultItem[month + 2] += pay;
            }
            resultItem[1] += pay;
        }
        
        resp.data.push(resultItem);
    }

    callback();
}

exports.nums = function(query, resp, callback) {
    var minSid = +query.minSid;
    var maxSid = +query.maxSid;

    var condition = {};
    if (query.hasOwnProperty('minTime')) {
        condition['ts'] = {'$gte': query.minTime};
        if (query.hasOwnProperty('maxTime')) {
            condition['ts']['$lt'] = query.maxTime;
        }
    }

    async.each(gServers.getSids(minSid, maxSid), function(sid, cb) {
        var db = gServers.getGameDB(sid);
        if (!db) {
            cb(); return;
        }
        
        var dbPay = db.collection('pay');
        dbPay.group({'openid':1}, condition, {sum:0}, "function(obj,prev){prev.sum += 1}", function(err, results) {
            if (err || !results) {
                cb(util.format('server %d dbPay error', sid)); return;
            }
            resp.data.push([sid, results.length]);
            cb();
        });
    }, function(err) {
        if (err) {
            resp.code = 1; resp.desc = err;
        }
        callback();
    });
}

exports.pay = function(query, resp, callback) {
    if (isNaN(query.minSid) || isNaN(query.maxSid) ||
        isNaN(query.minTime) || isNaN(query.maxTime)) {
        resp.code = 1; resp.desc = 'invalid params';
        callback(); return;
    }

    var minSid = query.minSid;
    var maxSid = query.maxSid;
    var minTime = query.minTime;
    var maxTime = query.maxTime;

    async.series([
        function(cb) {
            var sql = gStat.pool.format("SELECT * FROM pay WHERE sid BETWEEN ? AND ? AND day BETWEEN ? AND ?;", [
                minSid, maxSid,
                minTime, maxTime
            ]);
            gStat.pool.query(sql, function(err, res){
                if (err) cb(err);
                else {
                    resp.data = res || [];
                    cb(null);
                }
            });
        }
    ], function(err){
        if (err) {
            resp.code = 1;
            resp.desc = util.format("%j", err);
        }
        callback();
    });
};


exports.orders = function(query, resp, callback) {
    if (isNaN(query.minSid) || isNaN(query.maxSid) ||
        isNaN(query.minTime) || isNaN(query.maxTime)) {
        resp.code = 1; resp.desc = 'invalid params';
        callback(); return;
    }

    var minSid = +query.minSid;
    var maxSid = +query.maxSid;
    var minTime = +query.minTime;
    var maxTime = +query.maxTime;

    var now = new Date().zeroTime().getStamp();
    maxTime = Math.min(maxTime, now);

    var fileArr = [];
    fileArr.push(["服务器ID", "openid", "订单号", "gid", "cash", "时间戳", "时间", "amt", "状态\n"]);

    var abPath = path.join(gUserHome, gOrderPath);

    async.each(gServers.getSids(minSid, maxSid), function(sid, esCb) {
        var db = gServers.getGameDB(sid);
        if (!db) {
            esCb(); return;
        }

        var dbPay = db.collection('pay');

        var curTime = minTime;
        async.until(function(){
            return curTime >= maxTime;
        }, function(unCb){
            var timeStr = Date.createFromStamp(curTime).format("yyyy-MM-dd");
            var filePath = path.join(abPath, util.format("%s-%s.txt", sid, timeStr));

            fs.exists(filePath, function(exists){
                if (exists) {
                    fs.readFile(filePath, "utf8", function(err, data){
                        if (!err) {
                            fileArr.push(data);

                            curTime += 86400;
                            unCb(null);
                        } else {
                            _getDataFromDB(sid, dbPay, curTime, filePath, function(err, data){
                                if (err) {
                                    LOG(util.format("GET %d-%s ERROR", sid, timeStr));
                                } else {
                                    fileArr.push(data);
                                }

                                curTime += 86400;
                                unCb(null);
                            });
                        }
                    });
                } else {
                    _getDataFromDB(sid, dbPay, curTime, filePath, function(err, data){
                        if (err) {
                            LOG(util.format("GET %d-%s ERROR", sid, timeStr));
                        } else {
                            fileArr.push(data);
                        }

                        curTime += 86400;
                        unCb(null);
                    });
                }
            });

        }, function(err){
            esCb();
        });

    }, function(err) {
        resp.plain = true; // 下载文件
        resp.data = fileArr.join('');
        callback();
    });


    function _getDataFromDB(sid, db, curTime, filePath, fn) {
        var dayStart = curTime + "";
        var dayEnd = (curTime + 86400) + "";
        db.find({"ts":{"$gte": dayStart, "$lt": dayEnd}}).toArray(function(err, res){
            if (err) fn(err);
            else {
                var header = ["sid", "openid", "billno", "gid", "cash", "ts", "time", "amt", "state"];
                var data = [];
                res.forEach(function(v){
                    data.push([
                        sid,
                        v['openid'],
                        "'" + v['billno'] + "'",
                        v['gid'],
                        v['cash'],
                        v['ts'],
                        "'" + v['time'] + "'",
                        v['amt'],
                        v['state']
                    ]);
                });
                myUtil.exportCSV2(filePath, header.length, data, function(err, res){
                    if (err) LOG(err);
                    fn(null, res);
                });
            }
        });
    }
};


var payLayoutConfig = [
    0,
    100,
    500,
    1000,
    2000,
    5000,
    10000,
    20000,
    50000
];
exports.payLayout = function(query, resp, callback){
    if (isNaN(query.sid) ||
        !query.hasOwnProperty('minTime') || !query.hasOwnProperty('maxTime')) {
        resp.code = 1; resp.desc = 'invalid params';
        callback(); return;
    }

    var sid = +query.sid;
    var minTime = +query.minTime;
    var maxTime = +query.maxTime;

    var db = gServers.getGameDB(sid);
    if (!db) {
        resp.code = 1; resp.desc = 'invalid server';
        callback(); return;
    }

    var sumData = {};

    db.collection('pay').group({openid:1},
        {"ts":{
            "$gte":minTime + "",
            "$lt":maxTime + ""
        }
        },
        {sum:0},
        function(doc, prev) {
            prev.sum += +doc.amt;
        },
        function(err, res){
            if (err) {
                // 查询出错
                resp.code = 1; resp.desc = util.format("%j", err);
                callback();
            } else {

                res.forEach(function(value){
                    var sum = +value.sum;

                    var smallIdx = -1;
                    var largerIdx = -1;
                    for (var idx = 0; idx < payLayoutConfig.length; ++idx){
                        if (sum >= payLayoutConfig[idx]){
                            smallIdx = idx;
                        } else if (sum < payLayoutConfig[idx]) {
                            largerIdx = idx;
                            break;
                        }
                    }

                    if (smallIdx != -1) {
                        if (!sumData[smallIdx]) {
                            var desc = payLayoutConfig[smallIdx] + " -> ~";
                            if (largerIdx != -1)
                            {
                                desc = payLayoutConfig[smallIdx] + " -> " + payLayoutConfig[largerIdx];
                            }
                            sumData[smallIdx] = {
                                "desc" : desc,
                                "count" : 0
                            };
                        }

                        // 增加这一档人数
                        sumData[smallIdx].count++;
                    }
                });

                var retArr = [];
                for (var key in sumData)
                {
                    var idx = +key;
                    var desc = sumData[key].desc;
                    var count = +sumData[key].count;

                    retArr.push([idx, desc, count]);
                }

                resp.code = 0;
                resp.data = retArr;
                callback();
            }
        }
    );
};
